﻿using System;
using LoD.Server.Core.Interfaces;


namespace LoD.Server.Core {
    public struct WorldPoint2D : IWorldPoint2D, IComparable, IComparable<WorldPoint2D>
    {
        private int m_X;
        private int m_Y;

        public static readonly WorldPoint2D Zero = new WorldPoint2D(0, 0);

        public WorldPoint2D(int x, int y)
        {
            m_X = x;
            m_Y = y;
        }

        public WorldPoint2D(IWorldPoint2D p)
            : this(p.X, p.Y)
        {
        }

        public int X
        {
            get
            {
                return m_X;
            }
            set
            {
                m_X = value;
            }
        }

        public int Y
        {
            get
            {
                return m_Y;
            }
            set
            {
                m_Y = value;
            }
        }

        public override string ToString()
        {
            return String.Format("({0}, {1})", m_X, m_Y);
        }

        public static WorldPoint2D Parse(string value)
        {
            int start = value.IndexOf('(');
            int end = value.IndexOf(',', start + 1);

            string param1 = value.Substring(start + 1, end - (start + 1)).Trim();

            start = end;
            end = value.IndexOf(')', start + 1);

            string param2 = value.Substring(start + 1, end - (start + 1)).Trim();

            return new WorldPoint2D(Convert.ToInt32(param1), Convert.ToInt32(param2));
        }

        public int CompareTo(WorldPoint2D other)
        {
            int v = (m_X.CompareTo(other.m_X));

            if (v == 0)
                v = (m_Y.CompareTo(other.m_Y));

            return v;
        }

        public int CompareTo(object other)
        {
            if (other is WorldPoint2D)
                return this.CompareTo((WorldPoint2D)other);
            if (other == null)
                return -1;

            throw new ArgumentException();
        }

        public override bool Equals(object o)
        {
            if (o == null || !(o is IWorldPoint2D)) return false;

            var p = (IWorldPoint2D)o;

            return m_X == p.X && m_Y == p.Y;
        }

        public override int GetHashCode()
        {
            return m_X ^ m_Y;
        }

        public static bool operator ==(WorldPoint2D l, WorldPoint2D r)
        {
            return l.m_X == r.m_X && l.m_Y == r.m_Y;
        }

        public static bool operator !=(WorldPoint2D l, WorldPoint2D r)
        {
            return l.m_X != r.m_X || l.m_Y != r.m_Y;
        }

        public static bool operator ==(WorldPoint2D l, IWorldPoint2D r)
        {
            if (ReferenceEquals(r, null))
                return false;

            return l.m_X == r.X && l.m_Y == r.Y;
        }

        public static bool operator !=(WorldPoint2D l, IWorldPoint2D r)
        {
            if (ReferenceEquals(r, null))
                return false;

            return l.m_X != r.X || l.m_Y != r.Y;
        }

        public static bool operator >(WorldPoint2D l, WorldPoint2D r)
        {
            return l.m_X > r.m_X && l.m_Y > r.m_Y;
        }

        public static bool operator >(WorldPoint2D l, WorldPoint3D r)
        {
            return l.m_X > r.X && l.m_Y > r.Y;
        }

        public static bool operator >(WorldPoint2D l, IWorldPoint2D r)
        {
            if (Object.ReferenceEquals(r, null))
                return false;

            return l.m_X > r.X && l.m_Y > r.Y;
        }

        public static bool operator <(WorldPoint2D l, WorldPoint2D r)
        {
            return l.m_X < r.m_X && l.m_Y < r.m_Y;
        }

        public static bool operator <(WorldPoint2D l, WorldPoint3D r)
        {
            return l.m_X < r.X && l.m_Y < r.Y;
        }

        public static bool operator <(WorldPoint2D l, IWorldPoint2D r)
        {
            if (ReferenceEquals(r, null))
                return false;

            return l.m_X < r.X && l.m_Y < r.Y;
        }

        public static bool operator >=(WorldPoint2D l, WorldPoint2D r)
        {
            return l.m_X >= r.m_X && l.m_Y >= r.m_Y;
        }

        public static bool operator >=(WorldPoint2D l, WorldPoint3D r)
        {
            return l.m_X >= r.X && l.m_Y >= r.Y;
        }

        public static bool operator >=(WorldPoint2D l, IWorldPoint2D r)
        {
            if (ReferenceEquals(r, null))
                return false;

            return l.m_X >= r.X && l.m_Y >= r.Y;
        }

        public static bool operator <=(WorldPoint2D l, WorldPoint2D r)
        {
            return l.m_X <= r.m_X && l.m_Y <= r.m_Y;
        }

        public static bool operator <=(WorldPoint2D l, WorldPoint3D r)
        {
            return l.m_X <= r.X && l.m_Y <= r.Y;
        }

        public static bool operator <=(WorldPoint2D l, IWorldPoint2D r)
        {
            if (ReferenceEquals(r, null))
                return false;

            return l.m_X <= r.X && l.m_Y <= r.Y;
        }
    }
    
    public struct WorldPoint3D : IWorldPoint3D, IComparable, IComparable<WorldPoint3D> {
        public static readonly WorldPoint3D Zero = new WorldPoint3D(0, 0, 0);

        public WorldPoint3D(int x, int y, int z) : this() {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        public WorldPoint3D(IWorldPoint3D p)
            : this(p.X, p.Y, p.Z) { }

        public WorldPoint3D(IWorldPoint2D p, int z)
            : this(p.X, p.Y, z) { }

        #region IComparable Members

        public int CompareTo(object other) {
            if (other is WorldPoint3D) return this.CompareTo((WorldPoint3D)other);
            if (other == null) return -1;

            throw new ArgumentException();
        }

        #endregion

        #region IComparable<WorldPoint3D> Members

        public int CompareTo(WorldPoint3D other) {
            int v = (this.X.CompareTo(other.X));

            if (v == 0) {
                v = (this.Y.CompareTo(other.Y));

                if (v == 0) v = (this.Z.CompareTo(other.Z));
            }

            return v;
        }

        #endregion

        #region IWorldPoint3D Members

        public int X { get; set; }

        public int Y { get; set; }

        public int Z { get; set; }

        #endregion

        public override string ToString() { return String.Format("({0}, {1}, {2})", this.X, this.Y, this.Z); }

        public override bool Equals(object o) {
            if (o == null || !(o is IWorldPoint3D)) return false;

            var p = (IWorldPoint3D)o;

            return this.X == p.X && this.Y == p.Y && this.Z == p.Z;
        }

        public override int GetHashCode() { return this.X ^ this.Y ^ this.Z; }

        public static WorldPoint3D Parse(string value) {
            int start = value.IndexOf('(');
            int end = value.IndexOf(',', start + 1);

            string param1 = value.Substring(start + 1, end - (start + 1)).Trim();

            start = end;
            end = value.IndexOf(',', start + 1);

            string param2 = value.Substring(start + 1, end - (start + 1)).Trim();

            start = end;
            end = value.IndexOf(')', start + 1);

            string param3 = value.Substring(start + 1, end - (start + 1)).Trim();

            return new WorldPoint3D(Convert.ToInt32(param1), Convert.ToInt32(param2), Convert.ToInt32(param3));
        }

        public static bool operator ==(WorldPoint3D l, WorldPoint3D r) { return l.X == r.X && l.Y == r.Y && l.Z == r.Z; }

        public static bool operator !=(WorldPoint3D l, WorldPoint3D r) { return l.X != r.X || l.Y != r.Y || l.Z != r.Z; }

        public static bool operator ==(WorldPoint3D l, IWorldPoint3D r) {
            if (ReferenceEquals(r, null)) return false;

            return l.X == r.X && l.Y == r.Y && l.Z == r.Z;
        }

        public static bool operator !=(WorldPoint3D l, IWorldPoint3D r) {
            if (ReferenceEquals(r, null)) return false;

            return l.X != r.X || l.Y != r.Y || l.Z != r.Z;
        }
    }
}